package org.zhuzx.util.pool;

import java.lang.ref.WeakReference;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class AbstractCachedPool<E> {
	
	private AbstractFixedPool<E> corePool;
	private WeakReference<ConcurrentLinkedQueue<E>> cachePool;
	private AtomicInteger cacheSize = new AtomicInteger();
	
	public AbstractCachedPool(int coreSize) {
		corePool = new AbstractFixedPool<E>(coreSize) {
			protected E create() {
				return create();
			}
		};
		initCachePool();
	}
	
	private void initCachePool() {
		cachePool = new WeakReference<>(new ConcurrentLinkedQueue<E>());
		cacheSize.set(0);
	}
	
	protected abstract E create();
	
	public E get() {
		if (corePool.size() > 0) {
			E e = corePool.tryGet();
			if (e != null) {
				return e;
			}
		}
		return (cacheSize.get() > 0) ? takeFromCache() : create();
	}
	
	private E takeFromCache() {
		ConcurrentLinkedQueue<E> queue = cachePool.get();
		if (queue != null) {
			E e = queue.poll();
			if (e != null) {
				cacheSize.decrementAndGet();
				return e;
			}
		}
		return create();
	}
	
	public void giveBack(E e) {
		if (!corePool.giveBack(e)) {
			ConcurrentLinkedQueue<E> queue = cachePool.get();
			if (queue == null) {
				initCachePool();
				queue = cachePool.get();
			}
			queue.offer(e);
			cacheSize.incrementAndGet();
		}
	}

}